#Copyright (c) 2007-2008 Travis Fickett (tfickett at ufl dot edu)
#
#Permission is hereby granted, free of charge, to any person
#obtaining a copy of this software and associated documentation
#files (the "Software"), to deal in the Software without
#restriction, including without limitation the rights to use,
#copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the
#Software is furnished to do so, subject to the following
#conditions:
#
#The above copyright notice and this permission notice shall be
#included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
#OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
#WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
#OTHER DEALINGS IN THE SOFTWARE.

# This module is used in pynavigate, its not really tested tho :(
# This module owes much credit to this document:
# http://gpsd.berlios.de/NMEA.txt

#sentences supported
#	GLL, RMC, GSA, SDDPT
import re
import operator
class datafield():
	text = ""					# A textual representation of the numberical item with formatting
	numerical = 0
	ID = ""
	providedby = ""						# this is the talker that provided the sentence
	def __init__(self, provides):
		self.ID=provides
	def loadData(self, newdata):
		self.numerical = newdata
		self.text = self.ID+": "+str(self.numerical)
	
class pyNMEAparser():
	VERIFYCHECKSUMS = False			# preform verification on checksums ?
	
	TIME = datafield("UTC")
	TIME.loadData(1337)

	COG = datafield("COG")
	COG.loadData(256)

	SOG = datafield("SOG")
	SOG.loadData(5.4)
	
	LAT = datafield("LAT")
	LAT.loadData(-83.1234)
	
	LON = datafield("LON")
	LON.loadData(23.1234)
	
	FIX = datafield("FIX")
	FIX.text = "NotFixed"
	
	DBT = datafield("DBT")
	DBT.loadData(1.3)

	def verifyCheckSum(self, rawsentence):									# does not verify if it actually has a checksum
		'''Return True if checksum matches'''
		
		givenchecksum = rawsentence[-2:]  										#get the last 2 chars
		checksum = int(givenchecksum, 16) 										
		stripdata = rawsentence[1:-3]	  										#now slice off the $ and *.....
		calculatedchecksum = reduce(operator.xor, map(ord,stripdata))			#use the ord function to xor the chars together
		if calculatedchecksum == checksum:
			return True															# o snap they matched
		return False
	def parseRMC(self,rawsentence, provider):
		'''Used Internally but could be called direct'''
		split = re.split(",", rawsentence)
		
		self.COG.loadData(split[8])
		self.COG.providedby = provider
		
		self.SOG.loadData(float(split[7])*1.15)
		self.SOG.providedby = provider
		
		self.TIME.loadData(split[1])
		self.TIME.providedby = provider		
		
		self.LAT.loadData(split[3])
		self.LAT.providedby = provider
		
		self.LON.loadData(split[5])
		self.LON.providedby = provider
	
	def parseGLL(self, rawsentence, provider):
		'''Used Internally but could be called direct'''
		split = re.split(",", rawsentence)
		self.LAT.loadData(split[1])
		self.LON.loadData(split[3])
		self.TIME.loadData(split[5])
	def parseGSA(self, rawsentence, provider):
		'''Used Internally but could be called direct'''
		split = re.split(",", rawsentence)
		if split[2] == "1":
			self.FIX.text = str("FIX: NONE")
		if split[2] == "2":
			self.FIX.text = str("FIX: 2D")
		if split[2] == "3":
			self.FIX.text = str("FIX: 3D")
	def parseDPT(self, rawsentence, provider):
		'''Used Internally but could be called direct'''
		split = re.split(",", rawsentence)
		self.DBT.loadData(split[1])
	def parseSentence(self,rawsentence):
		'''Fill class data structures with parsed data.'''
		if not rawsentence:             # If we didn't get a sentence quit
			return
		if rawsentence[0] is not "$":
			return
		if self.VERIFYCHECKSUMS and not self.verifyCheckSum(rawsentace):
			return
		
		sentencesrc = rawsentence[1:3]								#determine who sent it GP, II, EC etc
		sentencetype = rawsentence[3:6]								# get the sentence type eg $..GGA*\*CK
		
		if sentencetype == "RMC":
			self.parseRMC(rawsentence, sentencesrc)
		if sentencetype == "GLL":
			self.parseGLL(rawsentence, sentencesrc)
		if sentencetype == "GSA":
			self.parseGSA(rawsentence, sentencesrc)
		if sentencetype == "DPT":
			self.parseDPT(rawsentence, sentencesrc)
